home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Very Best of Atari Inside
/
The Very Best of Atari Inside 1.iso
/
mint
/
mint99s
/
context.spp
< prev
next >
Wrap
Text File
|
1992-12-23
|
11KB
|
312 lines
;
; Copyright 1992 Eric R. Smith
; Copyright 1992 Atari Corporation
; All rights reserved.
%include "magic.i"
;
; routines for saving/restoring user contexts
;
; long build_context(struct context *sav, short fmt):
; Called from an interrupt handler (such as the trap #1 routine
; for system calls) saves the context of the interrupted
; routine. Assumes that no user registers have been changed
; since the interrupt, and that the PC and status register
; are still on the stack. Returns the stack pointer being used
; at the time of the interrupt **in register a1**.
; The fmt parameter is used on the 68000 to communicate the exception
; vector number; on >=68010 we use the vector offset from the frame.
;
; long save_context(struct context *sav):
; Saves the context of the calling routine in the area pointed
; to by sav. Save_context always returns 0 when initially called;
; this is so processes can (by suitably manipulating the
; saved registers) tell when the return from save_context is
; actually caused by restoring the context, e.g.:
; if (save_context(sav) == 0) { <<-- L1
; /* do some stuff */
; sav.regs[D0] = 1; /* for restore context */
; restore_context(sav); /* goes back to L1 */
; }
; else /* this is the second time through */
;
; void restore_context(struct context *sav):
; Restores a context previously saved by build_context or save_context.
; Since the program counter is part of the context, this function
; will never return (it's like longjmp()). NOTE: this function should
; be used only to change contexts _within_ the same program, since
; it does NOT flush the ATC. See change_context
;
; void change_context(struct context *sav):
; Restores a context previously saved by build_context or save_context
; for a different process. Unlike restore_context, this one *does*
; flush the ATC.
TEXT
XDEF _build_context
XDEF _save_context
XDEF _restore_context
XDEF _change_context
XDEF _set_mmu
XREF _fpu
XREF _framesizes
XREF _new_trace ; from intr.s
XREF _no_mem_prot
;
; set_mmu(crp,tc): called once, the first time a page table is built, to
; switch away from the MMU setup that came from the ROM and into the setup
; that we just built. The CRP is actually on the stack, and it's 8 bytes.
; The TC is four bytes at sp@(0xc). "Nulls" is here because we need to
; shove zeros into a few places.
;
; nulltc is in the data segment because otherwise GAS assembles PC-relative
; and that's not legal on 68030.
;
DATA
nulltc: dc.l 0
TEXT
_set_mmu:
pmove nulltc,tc ; turn off mmu
dc.l $f0390800,nulltc ; pmove nulltc,tt0
dc.l $f0390c00,nulltc ; pmove nulltc,tt1
pmove 4(sp),crp ; caution: crp is 8 bytes
pmove $c(sp),tc
rts
_build_context:
move.l a0,-(sp) ; save a0; we'll use it for scratch
move.l 8(sp),a0 ; get address of save area
tst.w _no_mem_prot ; is there memory protection?
bne.s noprot1
pmove crp,C_CRP(a0) ; save CRP from MMU
pmove tc,C_TC(a0) ; save TC from MMU
noprot1:
movem.l d0-d7/a0-a6,(a0) ; save registers D0-D7/A0-A6
clr.b C_PTRACE(a0) ; no pending traces, thanks!
lea 12(sp),a1 ; start of the interesting stack area
move.w (a1)+,d0 ; 68000 fake frame format
%ifndef ONLY030
move.w ($59e).w,d7 ; get process frame flag
bne.s nojunk ; we have some junk on the stack
move.w d0,C_SFMT(a0) ; save fake frame format
cmp.w #$8,d0 ; if bus error
beq.s group0
cmp.w #$c,d0 ; or address error
bne.s nojunk
group0: move.l (a1)+,C_INTERNAL(a0) ; stash it in the internal area
move.l (a1)+,C_INTERNAL+4(a0) ; if a debugger's interested
nojunk:
%endif
move.w (a1)+,d0 ; get SR of context
move.w d0,C_SR(a0) ; save it
move.l (a1)+,C_PC(a0) ; save PC of context
%ifndef ONLY030
tst.w d7 ; test longframe (AKP)
beq.s short1 ; short
%endif
tst.w _fpu ; is there a true FPU in the system
beq.s nofpu
fsave C_FSTATE(a0) ; save internal state frame
tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
beq.s nofpu ; skip programmer's model save
fmovem.x fp0-fp7,C_FREGS(a0) ; save data registers
fmovem.l fpcr/fpsr/fpiar,C_FCTRL(a0) ; and control registers
nofpu:
lea C_SFMT(a0),a2
move.w (a1)+,d1 ; fetch frame format word
move.w d1,(a2)+ ; and stash it away for later
lsr.w #8,d1 ; isolate the frame format identifier
lsr.w #4,d1
lea _framesizes,a3
move.b 0(a3,d1.w),d1
bra.s bcover
bcint: move.w (a1)+,(a2)+ ; copy CPU internal state
bcover: dbf d1,bcint
short1:
move.l a1,C_SSP(a0) ; a1 now points above the state frame
move.l usp,a1 ; save user stack pointer
move.l a1,C_USP(a0)
btst #13,d0 ; check for supervisor mode
beq.s L_CONT1 ; user mode; we already have stack in a1
L_SUPER1:
; moving from the save state buffer
; means not testing longframe again. (AKP)
move.l C_SSP(a0),a1 ; was using super stack pointer before interrupt
;
L_CONT1:
move.l ($408).w,C_TERM(a0) ; save GEMDOS terminate vector
move.l (sp)+,C_A0(a0) ; save old register a0
rts
_save_context:
move.l a0,-(sp) ; save a0
move.l 8(sp),a0 ; get address of context save area
tst.w _no_mem_prot
bne.s noprot2
pmove crp,C_CRP(a0) ; save the CRP from the MMU
pmove tc,C_TC(a0) ; save the TC from the MMU
noprot2:
; if running with a true coprocessor we need to save the FPU state
tst.w _fpu ; is there a true FPU in the system
beq.s nofpu2
fsave C_FSTATE(a0) ; save internal state frame
tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
beq.s nofpu2 ; skip programmer's model save
fmovem.x fp0-fp7,C_FREGS(a0) ; save data registers
fmovem.l fpcr/fpsr/fpiar,C_FCTRL(a0) ; and control registers
nofpu2:
; note: I am somewhat unsure of this assumption, viz that save_context
; can never be called in a situation where a co-processor
; mid-instruction stack frame would be required. I suspect this is a
; valid assumption, in which case the above FPU code is redundant, the
; next line is not however!
clr.w C_SFMT(a0) ; mark as a 4 word stack frame
clr.b C_PTRACE(a0) ; no pending traces, thanks!
movem.l d0-d7/a0-a6,(a0) ; save D0-D7/A0-A6
lea 8(sp),a1
move.l a1,C_SSP(a0) ; save supervisor stack pointer
; note that it should be pointing above the PC
move.l -4(a1),C_PC(a0) ; save PC
move.l usp,a1
move.l a1,C_USP(a0) ; save user stack pointer
move.w sr,d0
move.w d0,C_SR(a0) ; save status register
move.l ($408).w,C_TERM(a0) ; save GEMDOS terminate vector
move.l (sp)+,C_A0(a0) ; save old a0
moveq.l #0,d0 ; return 0
rts
_restore_context:
ori.w #$0700,sr ; mask interrupts
move.l 4(sp),a0 ; address of context save area
; Switch stacks now - starting now ssp is in the memory space of
; the process we're switching to. Thus, we can change memory context
; to there.
move.l C_SSP(a0),sp ; supervisor stack pointer
move.l C_USP(a0),a1
move.l a1,usp ; set user stack pointer
move.l C_TERM(a0),($408).w ; restore GEMDOS terminate vector
; Set memory context now: actually, this isn't necessary, since
; we're coming back to a context in the same process as is running
; now.
; tst.w _no_mem_prot
; bne.s noprot3
; pmove C_CRP(a0),crp ; restore MMU root pointer
; pmove C_TC(a0),tc ; restore MMU control register
noprot3:
%ifndef ONLY030
tst.w ($59e).w ; test longframe (AKP)
beq.s short3
%endif
; was moveq.l #0,d0, but I don't think that's what was desired */
moveq.l #0,d1
lea C_SFMT(a0),a1
move.w (a1)+,d0 ; fetch frame format word
move.w d0,d1 ; copy it for later
lsr.w #8,d1 ; isolate the frame format identifier
lsr.w #4,d1
lea _framesizes,a2
move.b 0(a2,d1.w),d1
sub.w d1,sp
sub.w d1,sp
move.l sp,a2
bra.s rcover
rcint: move.w (a1)+,(a2)+
rcover: dbf d1,rcint
move.w d0,-(sp) ; frame format identifier
; if running with a true coprocessor we need to restore the FPU state
tst.w _fpu ; is there a true FPU in the system
beq.s short3
tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
beq.s short4 ; skip programmer's model restore
fmovem.l C_FCTRL(a0),fpcr/fpsr/fpiar ; restore control registers
fmovem.x C_FREGS(a0),fp0-fp7 ; and data registers
short4: frestore C_FSTATE(a0) ; finally the internal state
short3:
move.l C_PC(a0),-(sp) ; push the PC
move.w C_SR(a0),d0 ; fetch status register
move.w d0,-(sp) ; push the status register
tst.b C_PTRACE(a0) ; check for a pending trace
movem.l (a0),d0-d7/a0-a6 ; restore registers d0-d7/a0-a6
beq.s notrace
jmp _new_trace
notrace:
rte ; jump back to old context
_change_context:
ori.w #$0700,sr ; mask interrupts
move.l 4(sp),a0 ; address of context save area
; Switch stacks now - starting now ssp is in the memory space of
; the process we're switching to. Thus, we can change memory context
; to there.
move.l C_SSP(a0),sp ; supervisor stack pointer
move.l C_USP(a0),a1
move.l a1,usp ; set user stack pointer
move.l C_TERM(a0),($408).w ; restore GEMDOS terminate vector
; Set memory context now
tst.w _no_mem_prot
bne.s noprot4
pmove C_CRP(a0),crp ; restore MMU root pointer
pmove C_TC(a0),tc ; restore MMU control register
noprot4:
%ifndef ONLY030
tst.w ($59e).w ; test longframe (AKP)
beq.s short6
%endif
; was moveq.l #0,d0, but I don't think that's what was desired */
moveq.l #0,d1
lea C_SFMT(a0),a1
move.w (a1)+,d0 ; fetch frame format word
move.w d0,d1 ; copy it for later
lsr.w #8,d1 ; isolate the frame format identifier
lsr.w #4,d1
lea _framesizes,a2
move.b 0(a2,d1.w),d1
sub.w d1,sp
sub.w d1,sp
move.l sp,a2
bra.s rcover2
rcint2: move.w (a1)+,(a2)+
rcover2: dbf d1,rcint2
move.w d0,-(sp) ; frame format identifier
; if running with a true coprocessor we need to restore the FPU state
tst.w _fpu ; is there a true FPU in the system
beq.s short3
tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
beq.s short5 ; skip programmer's model restore
fmovem.l C_FCTRL(a0),fpcr/fpsr/fpiar ; restore control registers
fmovem.x C_FREGS(a0),fp0-fp7 ; and data registers
short5: frestore C_FSTATE(a0) ; finally the internal state
short6:
move.l C_PC(a0),-(sp) ; push the PC
move.w C_SR(a0),d0 ; fetch status register
move.w d0,-(sp) ; push the status register
tst.b C_PTRACE(a0) ; check for a pending trace
movem.l (a0),d0-d7/a0-a6 ; restore registers d0-d7/a0-a6
beq.s notrace2
jmp _new_trace
notrace2:
rte ; jump back to old context
END